#include <stdio.h>
#include <stdbool.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <wait.h>

pid_t id;


//基于信号的回收子进程的方法
void handler(int signo)
{
    printf("signal: %d, i am father: %d\n", signo, getpid());
    sleep(5);

    while(true)
    {
        int ret = waitpid(-1, NULL, WNOHANG); //-1就是等待所有的子进程,在设置了WNOHANG之后，父进程就不会因为还有子进程没退出而阻塞(轮询)
        if (ret > 0)
        {
            printf("wait sucess ret: %d, who: %d\n", ret, id);
        }
        else break;//当没有子进程的时候，waitpid返回-1
    }

    printf("wait done....\n");
}
int main()
{
    //方法1
    //signal(SIGCHLD, handler);

    //方法2
    signal(17, SIG_IGN);//操作系统自动的回收子进程

    for (int i = 1; i <= 10; ++i)
    {
        id = fork();

        if (id == 0)
        {
            // child
            int cnt = 5;
            while (cnt--)
            {
                printf("i am childprocess: %d , father: %d\n", getpid(), getppid());
                sleep(1);
            }

            exit(1);
            // 子进程在退出的时候，回向父进程发送17(SIGCHLD)号信号
        }
    }

    // 在未受到信号的时候，父进程就在执行自己的代码
    while (true)
    {
        // printf(".........\n");
        sleep(1);
    }

    return 0;
}

// volatile int quit = 0;//volatile关键字可以保证CPU每次都需要从内存中读取数据，保证了内存的可见性

// void handler(int signo)
// {
//     printf("change quit from 0 to 1!\n");
//     quit = 1;
//     printf("quit : %d\n", quit);
// }

// int main()
// {
//     signal(2, handler);
//     //在编译时加上-O2 选项之后，编译器会做出优化，CPU在每次对quit进行检查时不再每次都从内存中读取数据到寄存器上，这就导致了
//     //即便是受到了2号信号之后再对quit进行更改，CPU也不会更新寄存器中quit的值，就导致了程序在收到了2号信号之后，quit就像是没有被修改一样
//     //继续的进行死循环下去。
//     while(!quit);

//     printf("main quit sucess!\n");

//     return 0;
// }